package base

/**
 * Created by Darkness1m on 2017/5/21.
 */
/*
fun base.main(args: Array<String>) {
    //val ==> 只读属性,一次赋值
    val base.getA:Int = 1//立即赋值
    val b = 2//自动推断出`Int`类型
    val base.getC:Int//如果没有初始值,类型不能省略
    base.getC = 3
//    println("base.getA = $base.getA ,b = $b ,base.getC = $base.getC")

    //可变变量
    var base.getX=5
    base.getX += 1
    println("base.getX = $base.getX")
}
*/

//属性:
class Address{

    var name: String = ""
    var street: String = ""
    var city:String = ""
    var size:Int = 0

    fun copyAddress(address: base.Address): base.Address {
        val result = base.Address()
        result.name="赵军豪"
        result.street = "琉璃街"
        result.city = "成都"
        return result
    }

    //初始化
    //变量
//    var allByDefault: Int?//变量必须显示初始化,隐含默认的getter和setter
    var initialized = 1//类型Int 默认 getter和setter
    //只读属性
    //只读属性不允许setter
//    val simple:Int?//
    val inferredType = 1//类型Int 默认getter

    //自定义访问器
    val isEmpty: Boolean
        get() = this.size==0
       /* set(value) {//val setter 报错
            copyAddress(base.Address())
        }*/
    var pocket: Int
        get(){
            return this.size
        }
//        set(value) = base.test(5)//有返回值的不能作为 '=' 类型的setter...有点坑
        set(value) {
            copyAddress(base.Address())//然而 有返回值的可以这样写...
        }
    fun test(value: Int){

    }

    var setterVisibility:Boolean = true
        private set//私有化setter

    var setterWithAnnotation:Any?=null
//        @Inject set  //使用注解

    //幕后字段backing field
    var counter = 0//初始器的值会直接写入到幕后字段中
        set(value) {
            if(value>0)
                field = value//field只能在属性的访问器内
        }
    //当至少有一个访问器使用默认实现,或是在自定义访问器中使用了field,则就会该属性自动生成一个幕后字段

    //这种就没有幕后字段
    val noBackingField:Boolean
        get() = this.size==0

    //幕后属性backing property
    private var _table:Map<String,Int>?=null
    public val table:Map<String,Int>
        get() {
            if(_table==null){
                _table = HashMap()
            }
            return _table?:throw AssertionError("已被其他线程设置为了null")
        }
}

//常量
// 1.位于顶层或是object的一个成员  (存疑.....反正不能定义在类里面)
// 2.必须使用String或原生类型初始化
// 3.没有自定义getter
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"
@Deprecated(base.SUBSYSTEM_DEPRECATED) fun foo(){}

//懒加载==>使用lateinit
//1.该修饰符只用于类体(非主构造函数)中声明的var属性
//2.该var属性没有自定义的getter和setter
//3.该var属性必须非null,且不能是原生类型
public class MyTest{
    lateinit var subject: base.Address

    /*@Setup fun setup(){//使用依赖注入来初始化,或者这里单元测试的setup初始化
        subject = base.Address()
    }

    @Test fun base.test(){
        subject.copyAddress(subject)
    }*/
}

//覆盖属性
open class AA{
    open val x:Int get() {return 0}
    open val y:Int get(){return 1}
}
class BB: base.AA(){
    override val x: Int
        get() = super.x
    override var y=2
        get() = 3
}

//类型检测
open class TypeDetection{//Any就相当于Java中的Object
    fun getStringLength(obj:Any):Int?{
        if(obj is String){
            return obj.length//经过判断后,不需要显式转换,编译器已经帮你做了
        }
        return null
    }
    fun getStringLength2(obj:Any):Int?{
        if(obj !is String) return null
        return obj.length
    }
    fun getStringLength3(obj:Any):Int?{
        if(obj is String && obj.length>0)//在&&就已经被转换为String了
            return obj.length
        return null
    }
    fun whenTest(x:Any?){
        when(x){
            is Int->print(x+1)
            is String-> print(x.length+1)
            is IntArray-> print(x.sum())
            is Unit->print("哈哈")
            else -> print("嘿嘿")
        }
    }
    //以下对于智能转换的场景还需要有对应的使用场景来熟悉....

    //对于变量而言,当编译器无法保证其值没有被修改时,不可智能转换
    fun variableTest(x:Any?){
        val a:String?//局部val,总是可以
        var b:String?//在检查和使用之前没有被修改、并且没有在lambda中被捕获
    }
    var b = 2//var属性绝不能被智能转换
    open val a=1//当属性为open,或者是有自定义getter时不可智能转换
        get(){
            field=2
            return field
        }
    //非安全的转换操作符   as
    fun unsafeConv(y:Any?,yy:Any?){
        val x:String = y as String
        val z:String? = yy as String?
    }
    //安全的  as?
    fun safeConv(y:Any?){
        val x:String? = y as? String
    }
}

/*
fun base.main(args: Array<String>) {
    base.TypeDetection().whenTest(null)
//    var base.getX = base.TypeDetection().getStringLength("你好啊")
//    var y = base.TypeDetection().getStringLength(1)
//    var z = base.TypeDetection().getStringLength(3)
//    println(base.getX)
//    println(y)
//    println(z)
//    println(listOf(Any()))
}*/

//编译期常量
//位于顶层
const val BAIDU_URL: String = "https://www.baidu.com"//1.使用String或是原生类型值初始化
//位于objcet内部
object Consts{
    val GOOGLE_URL: String = "google.com"//2.没有自定义getter
}

class TTT{
    lateinit var subject: base.TTT//延迟初始化
}
fun main(args: Array<String>) {

}